#pragma once
#include <iostream>
#include <string>
#include<jsoncpp/json/json.h>
using namespace std;

//客户端发送Request,服务端处理Request,将Response发送到客户端
//Request/Response为客户端与服务端约定好的结构化数据即协议
//服务端接收数据时,必须解决数据的完整性问题,保证收到的请求是完整的;
//只有接收到的数据是一条完整的请求才可进行反序列化

// 定制协议:
// 报文=报头+有效载荷
// 报头:"有效载荷的长度" 有效载荷: _x _oper _y
// 协议:"有效载荷的长度"\r\n"有效载荷"\r\n
// "len"\r\n"_x _oper _y"\r\n len:只表示有效载荷的长度 \r\n表示分割符,不参与统计
//读取数据

//添加协议报头 "len"\r\n"{json_str}"\r\n

const string SEP="\r\n";
string Encode(const string& json_str)
{
    int json_str_len=json_str.size();
    string proto_str=to_string(json_str_len);
    proto_str+=SEP;
    proto_str+=json_str;
    proto_str+=SEP;
    return proto_str;
}

//判定收到的数据是否存在完整的请求
//约定客户端发送的数据 "len"\r\n"{json_str}"\r\n"
string Decode(string& message)
{    
    size_t pos=message.find(SEP);
    //"len"
    if(pos==string::npos) return string();
    //"len"\r\n"...
    string lenstr=message.substr(0,pos);
    if(lenstr.empty()) return string();
    int packlen=stoi(lenstr);
    
    //meaasge中至少有多长的长度可以保证至少存在一个完整的报文
    int len=packlen+lenstr.size()+2*SEP.size();
    if(message.size()<len) return string();
    
    //至少存在一个完整的请求,从报文中提取有效载荷json_str
    string package=message.substr(pos+SEP.size(),packlen);
    
    //提取到第一条报文的有效载荷后将message从开头向后删除第一条完整报文
    //"len"\r\n"{json_str}"\r\n""len"\r\n"{json_str}"\r\n""len"\r\n"{json_str}"\r\n"
    //"len"\r\n"{json_str}"\r\n""len"\r\n"{json_str}"\r\n"

    // string& erase (size_t pos = 0, size_t len = npos);
    message.erase(0,len);
    return package;
}


class Request
{
public:
    Request()
    {}
    Request(int x,int y,char oper):_x(x),_y(y),_oper(oper)
    {}

    //序列化(将结构化数据转换为字符串)--->设置为输出型参数
    bool Serialize(string* out)
    {
        Json::Value root;
        root["x"]=_x;
        root["y"]=_y;
        root["oper"]=_oper;
        Json::FastWriter writer;
        *out=writer.write(root);
        return true;
    }

    //反序列化(将字符串转换为结构化数据)-->外部传递字符串
    bool Deserialize(const string& in)//如何保证服务端读取到的字符串是一个完整的字符串？---添加协议报头(报头:有效载荷的长度)
    {
        Json::Value root;
        Json::Reader reader;
        bool res=reader.parse(in,root);
        if(!res)
            return false;

        _x=root["x"].asInt();
        _y=root["y"].asInt();
        _oper=root["oper"].asInt();
        return true;
    }

    ~Request()
    {}
public:
    int _x;
    int _y;
    char _oper;//约定:_oper只能为"+ - * / %" 运算方式: _x _oper _y
};

//计算结果返回客户端`
class Response
{
public:
    Response()
    {}
    Response(int result,int code):_result(result),_code(code)
    {}

    //序列化(将结构化数据转换为字符串)--->设置为输出型参数
    bool Serialize(string* out)
    {
        Json::Value root;
        root["result"]=_result;
        root["code"]=_code;
        Json::FastWriter writer;
        *out=writer.write(root);
        return true;
    }

    //反序列化(将字符串转换为结构化数据)-->外部传递字符串
    bool Deserialize(const string& in)
    {
        Json::Value root;
        Json::Reader reader;
        bool res=reader.parse(in,root);
        if(!res)
            return false;
        _result=root["result"].asInt();
        _code=root["code"].asInt();
        return true;
    }

    ~Response()
    {}
public:
    int _result;//结果
    int _code;//0:表示计算结果可信  1:表示发生除0错误,结果不可信  2: 非法操作
};

//Requeset,Response为结构化数据暂时认为不可以直接发送到网络,结构化数据必须转换成字符串
//假设定义 Request req(10,20,'+');req对象也是按照字节存储而tcp是面向字节流的协议
//req对象直接发送到网络,为啥进行序列化与反序列化？
//os系统内部的协议将结构化的数据直接发送到网络
//应用层不采用此种做法,当客户端是windows操作系统,服务端为Linux操作系统
//操作系统结构体对齐的规则不尽相同,便导致未可预知的错误